package com.witframework.core;



import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.jci.listeners.FileChangeListener;
import org.apache.commons.jci.monitor.FilesystemAlterationListener;
import org.apache.commons.jci.monitor.FilesystemAlterationMonitor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class WitResourceLoaderListener  implements ServletContextListener {
	private static Log log = LogFactory.getLog(WitResourceLoaderListener.class);
	public final static String[] WEB_FOLDER_NAME = new String[]{"com/witframework/webroot/development:development"};	
	public final static String[] FRAMEWORK_FOLDER_NAME = new String[]{"com/witframework/baseapp/security","com/witframework/meta/view","com/witframework/webroot/framework"};
	private String classpath,webroot;
	public void contextInitialized(final ServletContextEvent evt) {
		ServletContext servletContext = evt.getServletContext();		
		webroot=StringUtils.replace(servletContext.getRealPath(""),File.separator,"/");
		classpath=webroot+"/WEB-INF/classes";
		extractResource(servletContext.getRealPath("")+ "/WEB-INF/lib/witframework.jar");
		extractResource(servletContext.getRealPath("")+ "/WEB-INF/lib/witframework-baseapp.jar");
	}
	private void extractResource(String r){
		String webPath;
		JarFile jarFile=null;
		try {
			String jarPath=r;		
			jarFile = new JarFile(jarPath);
			Enumeration<JarEntry> jarEntryEnum = jarFile.entries();
		    while (jarEntryEnum.hasMoreElements()) {
		    	JarEntry entry=jarEntryEnum.nextElement();		    	
		    	if(	inFrameWorkFolder(entry.getName())&&isWebResource(entry.getName())){		    		
		    		InputStream is=jarFile.getInputStream(entry);    
		    		writeFile(is,classpath+"/"+entry.getName());
		    	}else if((webPath=getWebRootFolder(entry.getName()))!=null&&isWebResource(entry.getName())){		    		
		    		InputStream is=jarFile.getInputStream(entry);    
		    		String[] path=StringUtils.split(webPath,":");
		    		writeFile(is,webroot+"/"+path[1]+entry.getName().substring(path[0].length()));
		    	}		    	
		    }
		}catch (IOException e) {		
			 new ReloadingViewResource().run();
			log.info(e.getMessage());
		}finally{
			try {jarFile.close();} catch (Exception e) {}
		}		
	}
	private boolean isWebResource(String name){
		return name.toLowerCase().endsWith(".jsp")||name.toLowerCase().endsWith(".htm")||
			name.toLowerCase().endsWith(".html");
	}
	private boolean inFrameWorkFolder(String name){
		for(String folder:FRAMEWORK_FOLDER_NAME){
			if(name.startsWith(folder))
				return true;
		}
		return false;
	}
	private String getWebRootFolder(String name){
		for(String folder:WEB_FOLDER_NAME){
			String[] path=StringUtils.split(folder,":");
			if(name.startsWith(path[0]))
				return folder;
		}
		return null;
	}
	public void contextDestroyed(final ServletContextEvent evt) { 
		
	}
	
	private void writeFile(final InputStream in,final String toPath) {		
		OutputStream out = null;
		try {
			File f=new java.io.File(toPath.substring(0,toPath.lastIndexOf("/")));
		    f.mkdirs();
			out = new BufferedOutputStream(new FileOutputStream(toPath));
			int len;
			byte [] buffer = new byte [4096];
			while ((len = in.read(buffer,0,buffer.length)) != -1) {
				out.write(buffer,0,len);
			}
			out.flush();
		} catch (Exception e) {
			log.error("Error writing file dude: " + e.getMessage());
		} finally {
			try { in.close(); out.close(); } catch (Exception e) { }
		}
	}
	private void writeFile(final File sourceFile,final String toPath) {	
		log.info("copy to:"+toPath);
		try {
			writeFile(new FileInputStream(sourceFile),toPath);
		} catch (FileNotFoundException e) {			
			e.printStackTrace();
		}
	}
	/**
	 * 检测应用程序目录下的页面文件变化
	 * @author wuxinyang
	 */
	class ReloadingViewResource {
		private final FilesystemAlterationMonitor fam = new FilesystemAlterationMonitor();
	    public void run() {	    	
	    	final URL url=ReloadingViewResource.class.getResource("/");
			final String basepath=url.getPath();			
	        final FilesystemAlterationListener listener = new FileChangeListener() {
	        @Override
			public void onFileChange( final File pFile ) {
	            	if(pFile.getName().endsWith(".jsp")||pFile.getName().endsWith(".html")||pFile.getName().endsWith(".htm")){
	            		copyFile(pFile);
	            	}
	        }
		    @Override
			public void onFileCreate( final File pFile) {	
	            	if(pFile.getName().endsWith(".jsp")||pFile.getName().endsWith(".html")||pFile.getName().endsWith(".htm")){
	            		copyFile(pFile);
	            	}
		    }	
		    @Override
			public void onFileDelete( final File pFile ) {		        	
	            	if(pFile.getName().endsWith(".jsp")||pFile.getName().endsWith(".html")||pFile.getName().endsWith(".htm")){
	            		String path=pFile.getPath();
	            		path=StringUtils.replace(path,File.separator,"/");
	            		String[] setPath=getPath(path);
	            		if(setPath!=null){	            			
	            			String toPath=getTargetWebPath(path,setPath);
		            		File deleteTarget=new File(toPath);
		            		deleteTarget.delete();
		            		log.info("删除文件："+toPath);
	            		}
	            	}
		        }

	         };
	        fam.addListener(new File(basepath), listener);
			fam.start();	        
	      }
	    private void copyFile(File pFile){
	    	String path=pFile.getPath();
	    	path=StringUtils.replace(path,File.separator,"/");	            		
    		String[] setPath=getPath(path);
    		if(setPath!=null){    			
    			String toPath=getTargetWebPath(path,setPath);
        		writeFile(pFile,toPath);
	        }
	    }
	    private String[] getPath(String name){	    	
			for(String folder:WEB_FOLDER_NAME){
				String[] path=StringUtils.split(folder,":");
				if(name.indexOf(path[0])>0)
					return path;				
			}
			return null;
		}
	    private String getTargetWebPath(String path,String[] setPath){
	    	String toPath=setPath[1]+path.substring(path.indexOf(setPath[0])+setPath[0].length());        	
        	return webroot+"/"+toPath;
	    }
	}
}
